import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:jm_flutter_common/jm_flutter_common.dart';

import 'jm_usb_platform_interface.dart';
import 'model/model.dart';

/// An implementation of [JmUsbPlatform] that uses method channels.
class MethodChannelJmUsb extends JmUsbPlatform {
  final tag = "MethodChannelJmUsb";

  /// The method channel used to interact with the native platform.
  final _channel = const MethodChannel('jm_usb_method_channel');
  final _connectStreamController = StreamController<bool>.broadcast();
  final _dataReceivedStreamController = StreamController<Uint8List>.broadcast();
  final _dataLengthStreamController = StreamController<int>.broadcast();

  @override
  Stream<bool> get connectStream => _connectStreamController.stream;

  @override
  Stream<Uint8List> get dataReceivedStream =>
      _dataReceivedStreamController.stream;

  @override
  Stream<int> get dataLengthStream => _dataLengthStreamController.stream;

  @override
  Future<bool> init() async {
    _channel.setMethodCallHandler((call) async {
      switch (call.method) {
        case "onConnect":
          final type = call.arguments as int;
          logd(tag, "设备连接: $type");
          _connectStreamController.add(true);
          break;
        case "onDisconnect":
          final type = call.arguments as int;
          logd(tag, "设备断开连接: $type");
          _connectStreamController.add(false);
          break;
        case "onDataReceived":
          //logd(tag, "收到数据: ${call.arguments}");
          _dataReceivedStreamController.add(Uint8List.fromList(call.arguments));

          break;
        case "onDataLength":
          //logd(tag, "收到数据长度: ${call.arguments}");
          _dataLengthStreamController.add(call.arguments as int);
          break;
        default:
          logw(tag, "没有找到方法:${call.method}");
      }
    });
    return true;
  }

  @override
  Future<void> exit() async {
    return;
  }

  @override
  Future<bool> quickConnectDevice(
    UsbDevice usbDevice, {
    int configurationIndex = 0,
    int interfaceIndex = 0,
    int? endpointInIndex,
    int? endpointOutIndex,
  }) async {
    return await _channel.invokeMethod('quickConnectDevice', {
      "identifier": usbDevice.identifier,
      "configurationIndex": configurationIndex,
      "interfaceIndex": interfaceIndex,
      "endpointInIndex": endpointInIndex,
      "endpointOutIndex": endpointOutIndex,
    });
  }

  @override
  Future<bool> quickConnectAccessory() async {
    return await _channel.invokeMethod('quickConnectAccessory');
  }

  @override
  Future<int> quickGetFileDescriptor(
    UsbDevice usbDevice, {
    int configurationIndex = 0,
    int interfaceIndex = 0,
    int? endpointInIndex,
    int? endpointOutIndex,
  }) async {
    return await _channel.invokeMethod('quickGetFileDescriptor', {
      'identifier': usbDevice.identifier,
      'configurationIndex': configurationIndex,
      'interfaceIndex': interfaceIndex,
      'endpointInIndex': endpointInIndex,
      'endpointOutIndex': endpointOutIndex,
    });
  }

  @override
  Future<List<UsbDevice>> getDeviceList() async {
    if (kIsIOS || kIsWeb) {
      logw(tag, "不支持的平台");
      return [];
    }
    List<Map<dynamic, dynamic>> devices =
        (await _channel.invokeListMethod('getDeviceList'))!;
    return devices.map((device) => UsbDevice.fromMap(device)).toList();
  }

  @override
  Future<List<UsbAccessory>> getAccessoryList() async {
    if (kIsIOS || kIsWeb) {
      logw(tag, "不支持的平台");
      return [];
    }
    // 修复类型转换问题，将Map<Object?, Object?>转换为Map<String, dynamic>
    List<Map<dynamic, dynamic>> accessories =
        (await _channel.invokeListMethod('getAccessoryList'))!;
    return accessories
        .map((accessory) =>
            UsbAccessory.fromMap(Map<String, dynamic>.from(accessory)))
        .toList();
  }

  @override
  Future<List<UsbDeviceDescription>> getDevicesWithDescription({
    bool requestPermission = true,
  }) async {
    var devices = await getDeviceList();
    var result = <UsbDeviceDescription>[];
    for (var device in devices) {
      result.add(await getDeviceDescription(
        device,
        requestPermission: requestPermission,
      ));
    }
    return result;
  }

  @override
  Future<UsbDeviceDescription> getDeviceDescription(
    UsbDevice usbDevice, {
    bool requestPermission = true,
  }) async {
    var result = await _channel.invokeMethod('getDeviceDescription', {
      'device': usbDevice.toMap(),
      'requestPermission': requestPermission,
    });
    return UsbDeviceDescription(
      device: usbDevice,
      manufacturer: result['manufacturer'],
      product: result['product'],
      serialNumber: result['serialNumber'],
    );
  }

  @override
  Future<bool> hasPermission(UsbDevice usbDevice) async {
    return await _channel.invokeMethod('hasPermission', usbDevice.toMap());
  }

  @override
  Future<bool> requestPermission(UsbDevice usbDevice) async {
    return await _channel.invokeMethod('requestPermission', usbDevice.toMap());
  }

  @override
  Future<String> getSerialNumber() async {
    return await _channel.invokeMethod('getSerialNumber');
  }

  @override
  Future<int> getFileDescriptor() async {
    return await _channel.invokeMethod('getFileDescriptor');
  }

  @override
  Future<bool> openDevice(UsbDevice usbDevice) async {
    return await _channel.invokeMethod('openDevice', usbDevice.toMap());
  }

  @override
  Future<void> closeDevice() {
    return _channel.invokeMethod('closeDevice');
  }

  @override
  Future<UsbConfiguration> getConfiguration(int index) async {
    var map = await _channel.invokeMethod('getConfiguration', {
      'index': index,
    });
    return UsbConfiguration.fromMap(map);
  }

  @override
  Future<bool> setConfiguration(UsbConfiguration config) async {
    return await _channel.invokeMethod('setConfiguration', config.toMap());
  }

  @override
  Future<bool> detachKernelDriver(UsbInterface intf) async {
    return true;
  }

  @override
  Future<bool> claimInterface(UsbInterface intf) async {
    return await _channel.invokeMethod('claimInterface', intf.toMap());
  }

  @override
  Future<bool> releaseInterface(UsbInterface intf) async {
    return await _channel.invokeMethod('releaseInterface', intf.toMap());
  }

  @override
  Future<Uint8List> bulkTransferIn(
      UsbEndpoint endpoint, int maxLength, int timeout) async {
    assert(endpoint.direction == UsbEndpoint.DIRECTION_IN,
        'Endpoint\'s direction should be in');

    List<dynamic> data = await _channel.invokeMethod('bulkTransferIn', {
      'endpoint': endpoint.toMap(),
      'maxLength': maxLength,
      'timeout': timeout,
    });
    return Uint8List.fromList(data.cast<int>());
  }

  @override
  Future<int> bulkTransferOut(
      UsbEndpoint endpoint, Uint8List data, int timeout) async {
    assert(endpoint.direction == UsbEndpoint.DIRECTION_OUT,
        'Endpoint\'s direction should be out');

    return await _channel.invokeMethod('bulkTransferOut', {
      'endpoint': endpoint.toMap(),
      'data': data,
      'timeout': timeout,
    });
  }

  @override
  Future<bool> controlTransfer({
    int requestType = 0,
    int request = 0,
    int value = 0,
    int index = 0,
    Uint8List? data,
  }) async {
    return await _channel.invokeMethod('controlTransfer', {
      'requestType': requestType,
      'request': request,
      'value': value,
      'index': index,
      'data': data ?? Uint8List(0),
    });
  }

  @override
  Future<bool> writeData(Uint8List data, int timeout) async {
    return await _channel.invokeMethod('writeData', {
      'data': data,
      'timeout': timeout,
    });
  }

  @override
  Future<Uint8List?> readData(int maxLength, int timeout) async {
    Uint8List? data = await _channel.invokeMethod('readData', {
      'maxLength': maxLength,
      'timeout': timeout,
    });
    return data;
  }

  @override
  Future<bool> accessoryWriteData(Uint8List data, int timeout) async {
    return await _channel.invokeMethod('accessoryWriteData', {
      'data': data,
      'timeout': timeout,
    });
  }

  @override
  Future<Uint8List?> accessoryReadData(int maxLength, int timeout) async {
    return await _channel.invokeMethod('accessoryReadData', {
      'maxLength': maxLength,
      'timeout': timeout,
    });
  }

  @override
  Future<void> startDataListening({
    int type = 0,
    int accumulatedBufferSize = 0,
    int requestCount = 8,
    int bufferSize = 16384,
  }) async {
    return await _channel.invokeMethod('startDataListening', {
      'type': type,
      'accumulatedBufferSize': accumulatedBufferSize,
      'requestCount': requestCount,
      'bufferSize': bufferSize
    });
  }

  @override
  Future<void> stopDataListening() async {
    return await _channel.invokeMethod('stopDataListening');
  }

  @override
  Future<void> setAutoDetachKernelDriver(bool enable) async {}
}
